Skip to content

spike(rust/fft): port compute_cross_correlation to Rust (#96) - #103

Merged
natashaannn merged 2 commits into
mainfrom
spike/issue-96-fft
Jul 12, 2026
Merged

spike(rust/fft): port compute_cross_correlation to Rust (#96)#103
natashaannn merged 2 commits into
mainfrom
spike/issue-96-fft

Conversation

@natashaannn

Copy link
Copy Markdown
Member

Summary

  • Implements next_power_of_two and compute_cross_correlation in spike/audio-sync/src/lib.rs, faithfully replicating AudioSyncer.js L145–186 using rustfft
  • Division by N is applied explicitly in the final map because rustfft's inverse transform does not normalize (unlike the JS FFT library)
  • Strictly scoped to spike/audio-sync/src/lib.rs per the hard constraint

Tests (5 inline #[cfg(test)])

Test Covers
next_power_of_two_known_values 1→1, 2→2, 3→4, 300,000→524288
cross_correlation_impulse_peak_at_k peak at N-K (circular negative-lag), output length == 128
cross_correlation_identical_inputs_peak_at_zero zero-lag case
cross_correlation_all_zeros_no_panic all-zero input, no panic
cross_correlation_single_sample_length_one edge case: result length 1

cargo test --manifest-path spike/audio-sync/Cargo.toml — 5/5 pass.

Notes

The impulse test asserts the peak at N - K (not K). IFFT(FA × conj(FB)) places a B-lags-A-by-K event at the circular negative-lag index N-K. The AC explicitly accepts this ("or N - K for negative lag"). A precondition doc comment notes that empty slices cause usize underflow.

Closes #96

🤖 Generated with Claude Code

Implements the FFT cross-correlation core from AudioSyncer.js (L145-186)
as a standalone Rust library function. Uses rustfft — no C FFT bindings.

The division by N in the final normalization is explicit because rustfft's
inverse transform does not normalize, unlike the JS fft library which
normalizes implicitly. Omitting the division would scale SNR comparisons
in validate_peak (#98) incorrectly.

The impulse test documents that IFFT(FA * conj(FB)) places a lag-K peak
at index N-K (the circular negative-lag form). This matches the JS formula
exactly and is consistent with how find_best_lag (#97) will interpret the
correlation array.

AC: all acceptance criteria from #96
S1: assert corr.len() == 128 in the impulse test so the output-length AC
is falsified for non-trivial inputs (previously only the single-sample
case had an explicit length check).

S2: document the len >= 1 precondition on compute_cross_correlation —
empty slices cause usize underflow on `len_a + len_b - 1`, which is
outside the AC scope but worth noting for callers.
@natashaannn
natashaannn merged commit 04c3489 into main Jul 12, 2026
1 check passed
@natashaannn
natashaannn deleted the spike/issue-96-fft branch July 12, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spike(rust/fft): port compute_cross_correlation to Rust

1 participant